Option Explicit

'################################################################
' Discriptor
' HashSet ISet 接口实现
'################################################################

Implements ISet

'################################################################
' Field
'################################################################
Private cache As Object

' cache.Keys 的缓存，以加速 Item 的访问速度
' 减少数组拷贝产生的消耗
' 每次发生 add/remove 操作时将该缓存置为 Empty
Private cis As Variant

'################################################################
' Constructor
'################################################################
Private Sub Class_Initialize()
    Set cache = UtilsCreateSysObj.createMap
    cis = Empty
End Sub

Private Sub Class_Terminate()
    Set cache = Nothing
End Sub

'################################################################
' Property
'################################################################
' 获取 set 内元素的数量
Public Property Get ISet_Count() As Long
    ISet_Count = cache.Count
End Property

'################################################################
' Function
'################################################################
' 按照索引来获取 set 内元素的数量
' 索引从 0 开始
Public Function ISet_Item(ByRef index as Variant) As Variant
    If IsEmpty(cis) Then
        cis = cache.Keys
    End If

On Error GoTo catch
    ISet_Item = cis(Int(index))
    Exit Function
catch:
    Err.Clear
    Set ISet_Item = cis(Int(index))
End Function

' 向 set 内添加元素。不会重复添加
Public Sub ISet_Add(ByRef val As Variant)
    ' 只在缓存中不存在指定元素时，才添加
    If cache.Exists(val) = False Then
        cache.Add val, ""

        ' 清空加速缓存
        cis = Empty
    End If
End Sub

' 检查 set 内是否存在指定元素
Public Function ISet_Exists(ByRef val As Variant) As Boolean
    ISet_Exists = cache.Exists(val)
End Function

' 从 set 内获取包含所有元素的数组
' 索引从 1 开始
Public Function ISet_Items() As Variant()
    ISet_Items = cache.Keys
End Function

' 删除 set 内的指定元素
Public Sub ISet_Remove(ByRef val As Variant)
    If cache.Exists(val) = True Then
        cache.Remove val

        ' 清空加速缓存
        cis = Empty
    End If
End Sub

' 删除 set 内的所有元素
Public Sub ISet_Clear()
    cache.RemoveAll

    ' 清空加速缓存
    cis = Empty
End Sub

' 克隆一个set
Public Function ISet_Clone() As ISet
    Dim result As HashSet
    Set result = New HashSet
    Dim v As Variant
    For Each v In cache.Keys
        result.ISet_Add v
    Next

    Set ISet_Clone = result
End Function

' 将数组的每个元素添加到 set 中
' @param arr 数组
Public Sub ISet_AddArray(ByRef arr As Variant)
    ' 如果数组长度为 0，则立刻结束
    Dim arrMin As Integer
    Dim arrMax As Integer
    arrMin = LBound(arr)
    arrMax = UBound(arr)
    If (arrMax - arrMin + 1) = 0 Then
        Exit Sub
    End If

    ' 保存数据
    Dim i As Integer
    For i = arrMin To arrMax
        ISet_Add arr(i)
    Next

    ' 清空加速缓存
    cis = Empty
End Sub

' 使用指定的分隔符，连接 set 内的所有元素
' 如果某个元素是一个 Object 类型的对象，无法生成字符串，只会为这个对象写入一个空格
' @param delimiter 分隔符
Public Function ISet_Join(ByRef delimiter As String) As String
    ISet_Join = UtilsArray.joinElem(cache.Keys, delimiter)
End Function

' 合并另一个 Set
' @param s 另一个 Set. 如果 s 和当前 Set 相同，将会立刻结束
Public Sub ISet_MergeSet(ByRef s As ISet)
    ' 1. 快速结束
    ' 1.1 如果 s 是空对象，则立刻结束
    If s Is Nothing Then
        Exit Sub
    End If
    ' 1.2 如果 s 和当前 Set 相同，将会立刻结束
    If s Is Me Then
        Exit Sub
    End If

    ' 2. 合并数据
    Dim v As Variant
    For Each v In s.Items
        ISet_Add v
    Next

    ' 3. 清空加速缓存
    cis = Empty
End Sub

' 从当前 set 中删除和另一个 Set 中相同的元素
' @param s 另一个 Set. 如果 s 和当前 Set 相同，将会直接清空当前 Set
Public Sub ISet_RemoveSet(ByRef s As ISet)
    ' 1. 快速结束
    ' 1.1 如果 s 是空对象，则立刻结束
    If s Is Nothing Then
        Exit Sub
    End If

    ' 1.2 如果 s 和当前 Set 相同，将会直接清空
    If s Is Me Then
        ISet_Clear

        ' 清空加速缓存
        cis = Empty
        Exit Sub
    End If

    ' 2. 删除数据
    Dim v As Variant
    For Each v In s.Items
        ISet_Remove v
    Next

    ' 3. 清空加速缓存
    cis = Empty
End Sub

' ==================================
' 转换成数组引用
' ==================================
' 合并 IObjArrayRef 对象中的所有元素
Public Sub ISet_mergeObjArrayRef(ByRef arr As IObjArrayRef)
    ' 1. 快速结束
    ' 1.1 如果 arr 是空对象，则立刻结束
    If arr Is Nothing Then
        Exit Sub
    End If

    Dim arrMaxIndex As Long
    arrMaxIndex = arr.MaxIndex
    If arrMaxIndex = -1 Then
        Exit Sub
    End If

    ' 2. 合并数据
    Dim v As Variant
    Dim i As Long
    With arr
        For i = 0 To arrMaxIndex
            ISet_Add .Item(i)
        Next
    End With

    ' 3. 清空加速缓存
    cis = Empty
End Sub

' 合并 IPrimitiveArrayRef 对象中的所有元素
Public Sub ISet_mergePrimitiveArrayRef(ByRef arr As IPrimitiveArrayRef)
    ' 1. 快速结束
    ' 1.1 如果 arr 是空对象，则立刻结束
    If arr Is Nothing Then
        Exit Sub
    End If

    Dim arrMaxIndex As Long
    arrMaxIndex = arr.MaxIndex
    If arrMaxIndex = -1 Then
        Exit Sub
    End If

    ' 2. 合并数据
    Dim v As Variant
    Dim i As Long
    With arr
        For i = 0 To arrMaxIndex
            ISet_Add .Item(i)
        Next
    End With

    ' 3. 清空加速缓存
    cis = Empty
End Sub

' 将 set 内的所有元素，保存到一个对象类型的数组引用中
Public Function ISet_toObjArrayRef() As IObjArrayRef
    Set ISet_toObjArrayRef = UtilsArrayRef.createRealObjArrayRef(cache.Count)

    If cache.Count = 0 Then
        Exit Function
    End If

    Dim v As Variant
    For Each v In cache.Keys
        ISet_toObjArrayRef.Add v
    Next
End Function

' 将 set 内的所有元素，保存到一个基础数据类型的数组引用中
Public Function ISet_toPrimitiveArrayRef() As IPrimitiveArrayRef
    Set ISet_toPrimitiveArrayRef = UtilsArrayRef.createRealPrimitiveArrayRef(cache.Count)

    If cache.Count = 0 Then
        Exit Function
    End If

    Dim v As Variant
    For Each v In cache.Keys
        ISet_toPrimitiveArrayRef.Add v
    Next
End Function